#pragma once
#include "thread.hpp"
#include "LockGuard.hpp"
#include "Log.hpp"
#include <queue>
#include <vector>
#include <string>

class threadData
{
public:
    threadData(const std::string &threadName)
        : _threadName(threadName)
    {
    }

    std::string _threadName;
};

const int default_threadNum = 5;

template <class T>
class ThreadPool
{
private:
    ThreadPool(int threadNum = default_threadNum)
        : _threadNum(threadNum)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);

        // 创建线程
        for (int i = 0; i < _threadNum; i++)
        {
            std::string threadname = "thread-";
            threadname += std::to_string(i + 1);

            threadData td(threadname);
            Thread<threadData> ttd(threadname, std::bind(&ThreadPool<T>::ThreadRun, this, std::placeholders::_1), td);
            _threads.push_back(ttd);

            lg.LogMessage(Info, "%s is created...\n", threadname.c_str());
        }
    }

    ThreadPool(const ThreadPool<T> &tp)=delete;
    const ThreadPool<T>& operator=(const ThreadPool<T> )=delete;
public:  
    static ThreadPool<T> *Getinstance()
    {
        if(instance==nullptr)
        {
            LockGuard lock(&_sig_mutex);
            //创建一个单列
            if(instance==nullptr)
            {
                lg.LogMessage(Info,"创建一个单例...\n");
                instance=new ThreadPool<T>();
            }
        }
        return instance;
    } 

    
    void ThreadWakeup()
    {
        // 唤醒
        pthread_cond_signal(&_cond);
    }

    void Push(T &in)
    {
        // 有数据就唤醒
        LockGuard lockguard(&_mutex);
        //lg.LogMessage(Debug, "other thread push a task, task is : %s\n", in.PrintTask().c_str());
        _q.push(in);

        ThreadWakeup();
    }

    void ThreadRun(threadData &td)
    {
        while (true)
        {
            T t;
            LockGuard loguard(&_mutex);
            {
                while (_q.empty())
                {
                    // 等待
                    ThreadWait(td);
                    lg.LogMessage(Debug, "%s is weakup\n", td._threadName.c_str());
                }

                t = _q.front();
                _q.pop();
            }
            // 处理
            t();
            //lg.LogMessage(Debug, "%s hander task %s,result is: %s\n", td._threadName.c_str(),
            // t.PrintTask().c_str(), t.PrintResult().c_str());
        }
    }

    void ThreadWait(threadData &td)
    {
        lg.LogMessage(Debug, "no task, %s is sleeping...\n", td._threadName.c_str());
        pthread_cond_wait(&_cond, &_mutex);
    }

    void Wait()
    {
        for (auto &thread : _threads)
        {
            thread.Join();
        }
    }

    bool Start()
    {
        for (auto &thread : _threads)
        {
            thread.Start();
            lg.LogMessage(Info, "%s is running...\n", thread.ThreadName().c_str());
        }
        return true;
    }

    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

private:
    std::queue<T> _q;
    std::vector<Thread<threadData>> _threads;
    int _threadNum;
    pthread_mutex_t _mutex;
    pthread_cond_t _cond;

    static ThreadPool<T> *instance;
    static pthread_mutex_t _sig_mutex;

};

template<class T>
ThreadPool<T>*ThreadPool<T>::instance=nullptr;
template<class T>
pthread_mutex_t ThreadPool<T>::_sig_mutex=PTHREAD_MUTEX_INITIALIZER;